#ifndef BASE_PROCESSOR_H_
#define BASE_PROCESSOR_H_
#include <mutex>
#include <string>

#include "common/perception_defs.h"
#include "postprocess/common/common_func.h"
#include "postprocess/common/common_var.h"
#include "postprocess/common/object_track.h"
#include "postprocess/matcher/matcher.h"

class BaseProcessor {
 public:
  BaseProcessor() noexcept;
  BaseProcessor(BaseProcessor const &) = delete;
  BaseProcessor &operator=(BaseProcessor const &) = delete;
  BaseProcessor(BaseProcessor &&) = delete;
  BaseProcessor &operator=(BaseProcessor &&) = delete;
  virtual ~BaseProcessor();

  ///@brief set class vec
  ///@return void
  void SetClassFlag(const std::vector<uint32_t> &vec) noexcept;
  void AddClassFlag(uint32_t flag) noexcept;
  void AddAndClearClassFlag(uint32_t flag) noexcept;

 protected:
  // @brief transform tracker from bbox
  // @params[IN]
  // @params[IN]
  // @params[OUT]
  // @note trandform without transform matrix
  void transform_tracker_from_bbox(TrackedObjectPtr *tracker,
                                   const BoundingBox &bbox) noexcept;

  // @brief transform tracker from bbox
  // @params[IN]
  // @params[IN]
  // @params[OUT]
  // @note trandform with transform matrix
  void transform_tracker_from_bbox(
      TrackedObjectPtr *tracker, const BoundingBox &bbox,
      const Eigen::Matrix4f &transformed_matrix) noexcept;

  // @brief predict trackder
  // @params[IN]
  // @params[IN]
  // @params[OUT]
  void predict(const autodrive::perception::PerceptionResult &percetion,
               double time_diff) noexcept;

  /// @brief create bbox index form : 0 ~ n-1
  /// @param
  /// @return
  void range(
      const autodrive::perception::fixed_array<BoundingBox, kMaxBoundingBoxNum>
          &dl_boxes,
      std::vector<std::int32_t> &objects_index) noexcept;

  /// @brief constrcut tracked_object from lidar_object
  /// @param
  /// @return
  /// @note constrcut tracked object without transform matrix
  void construct_tracked_objects(
      const autodrive::perception::fixed_array<BoundingBox, kMaxBoundingBoxNum>
          &dl_boxes,
      std::vector<TrackedObjectPtr> *tracked_objects,
      std::uint64_t timestamp) noexcept;

  /// @brief constrcut tracked_object from lidar_object
  /// @param
  /// @return
  /// @note constrcut tracked object without transform matrix
  void construct_tracked_objects(
      const autodrive::perception::fixed_array<BoundingBox, kMaxBoundingBoxNum>
          &dl_boxes,
      std::vector<TrackedObjectPtr> *tracked_objects, std::uint64_t timestamp,
      const Eigen::Matrix4f &transformed_matrix) noexcept;

  /// @brief classify object based on different type and add number
  /// @param
  /// @return
  void classify_tracked_objects(const BoundingBox &bbox,
                                uint32_t &num_vehicle_tracker,
                                uint32_t &num_pedestrain_tracker,
                                uint32_t &num_other_tracker) noexcept;

  /// @brief compute predicted states of maintained tracks
  /// @param[OUT] tracks_predict: predicted states of maintained tracks
  /// @param[IN] time_diff: time interval for predicting
  /// @return nothing
  void compute_tracks_predict(std::vector<Eigen::VectorXf> &tracks_predict,
                              double time_diff,
                              ObjectTrackSet &object_tracks_set);

  /// @brief create new tracker object
  /// @param void
  /// @return void
  void create_new_tracks(
      std::vector<TrackedObjectPtr> const &new_objects,
      std::vector<std::int32_t> const &unassigned_objects_index,
      ObjectTrackSet &object_tracks_set) noexcept(false);

  /// @brief create new tracker object
  /// @param void
  /// @return void
  void create_new_tracks(
      std::vector<TrackedObjectPtr> const &new_objects,
      std::vector<std::int32_t> const &unassigned_objects_index,
      ObjectTrackSet &object_tracks_set,
      PostProcessorSettings const &settings) noexcept(false);

  /// @brief update assigned tracks
  /// @params[IN] tracks_predict: predicted states of maintained tracks
  /// @params[IN] new_objects: recently detected objects
  /// @params[IN] assignments: assignment pair of <track, object>
  /// @params[IN] time_diff: time interval for updating
  /// @return nothing
  void update_assigned_tracks(std::vector<TrackedObjectPtr> *new_objects,
                              std::vector<TrackObjectPair> const &assignments,
                              double time_diff,
                              ObjectTrackSet &object_tracks_set);

  /// @brief update tracks without matched objects
  /// @param[IN] tracks_predict: predicted state of maintained tracks
  /// @param[IN] unassigned_tracks: index of unassigned tracks
  /// @param[IN]
  /// @param[IN]
  /// @param[IN] time_diff: time interval for updating
  /// @return nothing
  void update_unassigned_tracks(
      std::vector<Eigen::VectorXf> const &tracks_predict,
      std::vector<std::int32_t> const &unassigned_tracks, double time_diff,
      ObjectTrackSet &object_tracks_set);

  /// @brief delete lost tracks
  /// @return nothing
  void delete_lost_tracks(ObjectTrackSet &object_tracks_set) noexcept(false);
  /// @brief class flag
  std::vector<uint32_t> class_vec_;
  /// @brief track prediction
  //   autodrive::perception::fixed_array<TrackedObject, kMaxTrackerObjectNum>
  //       tracker_prediction_objects_;
  /// @brief proseccor flag
  ProcessorClass processor_flag_;
};

#endif  // BASE_PROCESSOR_H_
